#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Error.h"

#include "String.h"
#include "System.h"
#include "Env.h"
#include "ET_stdio.h"

const char *cAssertMsg= "%s violated at line %d of `%s'.\n";

static ErrorHandlerFunc errorhandler= DefaultErrorHandler;
static int gAssertLevel= -1;

ErrorHandlerFunc SetErrorHandler(ErrorHandlerFunc newhandler)
{
	ErrorHandlerFunc oldhandler= errorhandler;
	errorhandler= newhandler;
	return oldhandler;
}

ErrorHandlerFunc GetErrorHandler()
{
	return errorhandler;
}

void AbstractMethod(const char *s)
{
	Warning(s, "this method should't be called!");
}

void MayNotUse(const char *s)
{
	Warning(s, "may not use");
}

void DefaultErrorHandler(int level, bool abort, const char *location,
								const char *msg)
{
	char *type= "Warning";
	if (level < Env::GetValue("System.IgnoreLevel", cError))
		return;
	if (level >= cFatal)
		type= "Fatal";
	else if (level >= cSysError)
		type= "SysError";
	else if (level >= cError)
		type= "Error";
		
	fprintf (stderr, "%s in <%s>: %s\n", type, location, msg);
	fflush (stderr);
	if (abort) {
		fprintf (stderr, "aborting\n");
		fflush (stderr);
		gSystem->Abort();
	}
}

void ErrorHandler(int level, const char *location, const char *fmt, va_list ap)
{
	char buf[1024], *bp;

	vsprintf(buf, fmt, ap);
	if (level >= cSysError && level < cFatal)
		bp= form("%s (%s)", buf, gSystem->GetError());
	else
		bp= buf;
	if (level != cFatal) {
		int al= Env::GetValue("System.AbortLevel", cSysError);
		errorhandler(level, level >= al, location, bp);
	} else
		DefaultErrorHandler(level, TRUE, location, bp);
}

void Error(const char *location, const char *va_(fmt), ...)
{
	va_list ap;
	va_start(ap,va_(fmt));
	ErrorHandler(cError, location, va_(fmt), ap);
	va_end(ap);
}

void SysError(const char *location, const char *va_(fmt), ...)
{
	va_list ap;
	va_start(ap, va_(fmt));
	ErrorHandler(cSysError, location, va_(fmt), ap);
	va_end(ap);
}

void Warning(const char *location, const char *va_(fmt), ...)
{
	va_list ap;
	va_start(ap,va_(fmt));
	ErrorHandler(cWarning, location, va_(fmt), ap);
	va_end(ap);
}

void Fatal(const char *location, const char *va_(fmt), ...)
{
	va_list ap;
	va_start(ap,va_(fmt));
	ErrorHandler(cFatal, location, va_(fmt), ap);
	va_end(ap);
}

int GetAssertLevel()
{
	if (gAssertLevel == -1 && gSystem)
		gAssertLevel= Env::GetValue("System.AssertLevel", 0);
	return gAssertLevel;
}

int SetAssertLevel(int l)
{
	int old= gAssertLevel;
	gAssertLevel= l;
	return old;
}

